﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Dir
{
    class PAS_Formatter
    {
        private enum ParseState
        {
            Null, Identifier, Keyword, Number, Chars, OneLineComment, MultiLineComment
        }
        
        private string source = null;
        private ParseState state = ParseState.Null;

        public PAS_Formatter(string source)
        {
            this.source = source;
        }

        public string Parse()
        {
            StringBuilder formatted = new StringBuilder();
            StringBuilder word = new StringBuilder();
            int i = 0;
            while (i <= source.Length)
            {
                char ch = i < source.Length ? source[i] : (char)0,
                     prevCh = i > 0 ? source[i - 1] : (char)0,
                     nextCh = i < source.Length - 1 ? source[i + 1] : (char)0;
                switch (state)
                {
                    case ParseState.Null:
                        if (char.IsLetter(ch))
                        {
                            state = ParseState.Identifier;
                            word = new StringBuilder();
                            word.Append(ch);
                        }
                        else if (char.IsDigit(ch))
                        {
                            state = ParseState.Number;
                            word = new StringBuilder();
                            word.Append(ch);
                        }
                        else if (ch == '\'')
                        {
                            state = ParseState.Chars;
                            word = new StringBuilder();
                            word.Append(ch);

                        }
                        else if (ch == '/' && nextCh == '/')
                        {
                            state = ParseState.OneLineComment;
                            word = new StringBuilder();
                            word.Append(ch);
                        }
                        else if ((ch == '(' && nextCh == '*') || ch == '{')
                        {
                            state = ParseState.MultiLineComment;
                            word = new StringBuilder();
                            word.Append(ch);
                        }
                        else if (i < source.Length)
                            formatted.Append(ch);
                        break;
                    case ParseState.Identifier:
                        string w = word.ToString();
                        if (char.IsLetterOrDigit(ch))
                            word.Append(ch);
                        else if (AuditKeyWords.KeyWordsPas(w))
                        {
                            state = ParseState.Keyword;
                            i--;
                        }
                        else
                        {
                            formatted.Append(word);
                            state = ParseState.Null;
                            i--;
                        }
                        break;
                    case ParseState.Keyword:
                        formatted.Append("<span class = \"colorB\">").Append(word).Append("</span>");
                        state = ParseState.Null;
                        i--;
                        break;
                    case ParseState.Number:
                        if (char.IsLetterOrDigit(ch) || ch == '.')
                            word.Append(ch);
                        else
                        {
                            formatted.Append("<span class = \"number\">").Append(word).Append("</span>");
                            state = ParseState.Null;
                            i--;
                        }
                        break;
                    case ParseState.Chars:
                        if (ch == '\'' || (ch == '\n' && prevCh == '\r'))
                        {
                            word.Append(ch);
                            if (ch == '\n' && prevCh == '\r')
                            {
                                formatted.Append(word);
                                state = ParseState.Null;
                            }
                            else
                            {
                                if (prevCh != '\\')
                                {
                                    formatted.Append("<span class = \"string\">").Append(word).Append("</span>");
                                    state = ParseState.Null;
                                }
                            }
                        }
                        else
                            word.Append(ch);
                        break;
                    case ParseState.OneLineComment:
                        if (ch != '\r' && ch != '\n')
                            word.Append(ch);
                        else
                        {
                            formatted.Append("<span class = \"comment\">").Append(word).Append("</span>");
                            state = ParseState.Null;
                            i--;
                        }
                        break;
                    case ParseState.MultiLineComment:
                        if ((ch == ')' && prevCh == '*')||(ch == '}') || (i == source.Length - 1))
                        {
                            word.Append(ch);
                            formatted.Append("<span class = \"comment\">").Append(word).Append("</span>");
                            state = ParseState.Null;
                        }
                        else
                        {
                            word.Append(ch);
                        }

                        break;
                    default:
                        break;
                }
                i++;
            }
            return formatted.ToString();
        }

        public static string Parse(string source)
        {
            PAS_Formatter f = new PAS_Formatter(source);
            return f.Parse();
        }

    }
}
